﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;

namespace DotNetCSharp
{
    public partial class FuxiType
    {
        enum Strategy
        {
            Basic,
            Trap,
            Jackel
        }

        public AgentType Agent { get; set; }
        FrameData _frameData;
        HandData _handData;
        double winOdds, loseOdds, potOdds;
        bool _flopCheckRaise, _flopCheckRaised, _turnCheckRaise, _turnCheckRaised, _riverCheckRaise;
        bool oppNeverRaised, shouldRaisePreflop, shouldBetFlop, shouldCbet, shouldDbet;
        int _outs;
        Strategy strategy;
        public FuxiType()
        {
        }
        public void NewHand()
        {
            _flopCheckRaise = _flopCheckRaised = false;
            _turnCheckRaise = _turnCheckRaised = false;
            _riverCheckRaise = false;
            oppNeverRaised = false;
            shouldRaisePreflop = shouldBetFlop = shouldCbet = shouldDbet = false;
            strategy = GetStrategy();
        }
        Strategy GetStrategy()
        {
            var lastHands = Agent.LastHands;
            var allHands = Agent.AllHands;

            int numOppPreflopRaise = lastHands.Where(hand => hand.NumOppRaisedPreflop > 0).Count();
            int numOppFlopRaise = lastHands.Where(hand => hand.NumOppRaisedFlop > 0).Count();
            int numOppTurnRaise = lastHands.Where(hand => hand.NumOppRaisedTurn > 0).Count();
            int numFlopSeen = lastHands.Where(hand => hand.LastRound >= G.Flop).Count();
            int numTurnSeen = lastHands.Where(hand => hand.LastRound >= G.Turn).Count();


            int numFuxiSbRaisedPreflop = allHands.Where(hand => (
                             hand.HavePosition &&
                             hand.NumFuxiRaisedPreflop == 1 &&
                             hand.NumOppRaisedPreflop == 0)
                    ).Count();
            int numOppBbFoldPreflop = allHands.Where(hand => (hand.LastRound == G.Preflop &&
                                         hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0)
                                ).Count();
            int numFuxiBbRaisedPreflop = allHands.Where(hand => (
                                        !hand.HavePosition &&
                                        hand.NumFuxiRaisedPreflop == 1 &&
                                        hand.NumOppRaisedPreflop == 0)
                                ).Count();
            int numOppSbFoldPreflop = allHands.Where(hand => (hand.LastRound == G.Preflop &&
                                         !hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0)
                                ).Count();
            int numFuxiSbRaisedFlop = allHands.Where(hand => (
                                         hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumOppRaisedFlop == 0)
                                ).Count();
            int numOppBbFoldFlop = allHands.Where(hand => (hand.LastRound == G.Flop &&
                                         hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumOppRaisedFlop == 0)
                                ).Count();
            int numFuxiBbRaisedFlop = allHands.Where(hand => (
                                         !hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumOppRaisedFlop == 0)
                                ).Count();
            int numOppSbFoldFlop = allHands.Where(hand => (hand.LastRound == G.Flop &&
                                         !hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumOppRaisedFlop == 0)
                                ).Count();
            int numFuxiSbCbet = allHands.Where(hand => (
                                                     hand.HavePosition &&
                                                     hand.NumFuxiRaisedPreflop == 1 &&
                                                     hand.NumOppRaisedPreflop == 0 &&
                                                     hand.NumFuxiRaisedFlop == 1 &&
                                                     hand.NumOppRaisedFlop == 0)
                                            ).Count();
            int numOppBbFoldCbet = allHands.Where(hand => (
                                                     hand.HavePosition &&
                                                     hand.LastRound == G.Flop &&
                                                     hand.NumFuxiRaisedPreflop == 1 &&
                                                     hand.NumOppRaisedPreflop == 0 &&
                                                     hand.NumFuxiRaisedFlop == 1 &&
                                                     hand.NumOppRaisedFlop == 0)
                                            ).Count();
            int numFuxiBbCbet = allHands.Where(hand => (
                                                     !hand.HavePosition &&
                                                     hand.NumFuxiRaisedPreflop == 1 &&
                                                     hand.NumOppRaisedPreflop == 0 &&
                                                     hand.NumFuxiRaisedFlop == 1 &&
                                                     hand.NumOppRaisedFlop == 0)
                                            ).Count();
            int numOppSbFoldCbet = allHands.Where(hand => (
                                                     !hand.HavePosition &&
                                                     hand.LastRound == G.Flop &&
                                                     hand.NumFuxiRaisedPreflop == 1 &&
                                                     hand.NumOppRaisedPreflop == 0 &&
                                                     hand.NumFuxiRaisedFlop == 1 &&
                                                     hand.NumOppRaisedFlop == 0)
                                            ).Count();
            int numFuxiSbDbet = allHands.Where(hand => (
                                         hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedFlop == 0 &&
                                         hand.NumFuxiRaisedTurn == 1 &&
                                         hand.NumOppRaisedTurn == 0)
                                ).Count();
            int numOppBbFoldDbet = allHands.Where(hand => (
                                         hand.HavePosition &&
                                         hand.LastRound == G.Turn &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedFlop == 0 &&
                                         hand.NumFuxiRaisedTurn == 1 &&
                                         hand.NumOppRaisedTurn == 0)
                                            ).Count();
            int numFuxiBbDbet = allHands.Where(hand => (
                                         !hand.HavePosition &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedFlop == 0 &&
                                         hand.NumFuxiRaisedTurn == 1 &&
                                         hand.NumOppRaisedTurn == 0)
                                ).Count();
            int numOppSbFoldDbet = allHands.Where(hand => (
                                         !hand.HavePosition &&
                                         hand.LastRound == G.Turn &&
                                         hand.NumFuxiRaisedPreflop == 1 &&
                                         hand.NumOppRaisedPreflop == 0 &&
                                         hand.NumFuxiRaisedFlop == 1 &&
                                         hand.NumOppRaisedFlop == 0 &&
                                         hand.NumFuxiRaisedTurn == 1 &&
                                         hand.NumOppRaisedTurn == 0)
                                            ).Count();

            if (_handData.HavePosition)
            {
                if (numOppBbFoldPreflop > 0.5 * numFuxiSbRaisedPreflop)
                {
                    shouldRaisePreflop = true;
                }
                if (numOppBbFoldFlop > 0.5 * numFuxiSbRaisedFlop)
                {
                    shouldBetFlop = true;
                }
                if (numOppBbFoldCbet > 0.5 * numFuxiSbCbet)
                {
                    shouldCbet = true;
                }
                if (numOppBbFoldDbet > 0.57 * numFuxiSbDbet)
                {
                    shouldDbet = true;
                }
            }
            else
            {
                if (numOppSbFoldPreflop > 0.34 * numFuxiBbRaisedPreflop)
                {
                    shouldRaisePreflop = true;
                }
                if (numOppSbFoldFlop > 0.34 * numFuxiBbRaisedFlop)
                {
                    shouldBetFlop = true;
                }
                if (numOppSbFoldCbet > 0.4 * numFuxiBbCbet)
                {
                    shouldCbet = true;
                }
                if (numOppSbFoldDbet > 0.5 * numFuxiBbDbet)
                {
                    shouldDbet = true;
                }
            }
            if (lastHands.Count < G.Window)
            {
                return Strategy.Basic;
            }
            else
            {
                if (numOppPreflopRaise > 0.4 * lastHands.Count() ||
                numOppFlopRaise > 0.4 * numFlopSeen ||
                numOppTurnRaise > 0.4 * numTurnSeen)
                {
                    return Strategy.Trap;
                }
                else
                {
                    return Strategy.Basic;
                }
            }

        }
        public void MakeDecision(FrameData frameData,HandData handData)
        {
            try
            {
                _frameData = frameData;
                _handData = handData;
                oppNeverRaised = (_handData.NumOppRaisedPreflop == 0 && _handData.NumOppRaisedFlop == 0 &&
                                   _handData.NumOppRaisedTurn == 0 && _handData.NumOppRaisedRiver == 0);
                if (_frameData.Round != G.River)
                {
                    winOdds = HandEvaluator.GetFinalWinOdds(_frameData.Pocket, _frameData.Board);
                }
                else
                {
                    winOdds = HandEvaluator.GetCurrentWinOdds(_frameData.Pocket, _frameData.Board);
                    loseOdds = HandEvaluator.GetCurrentLoseOdds(_frameData.Pocket, _frameData.Board);
                }
                double chipsToCall = _frameData.OpponentBet - _frameData.MyBet;
                potOdds = chipsToCall / (chipsToCall + (double)_frameData.Pot);
                if (_frameData.Round == G.Preflop)
                {
                    MakePreflopDecision();
                }
                else if (_frameData.Round == G.Flop)
                {
                    if (!_handData.HavePosition && _handData.NumOppRaisedPreflop == 1 && _handData.NumOppRaisedFlop == 0 &&
                        !_flopCheckRaise && strategy == Strategy.Trap)
                    {
                        _flopCheckRaise = true;
                    }
                    else
                    {
                        _flopCheckRaise = false;
                    }
                    MakeFlopDecision();
                }
                else if (_frameData.Round == G.Turn)
                {
                    if (!_handData.HavePosition && _handData.NumOppRaisedFlop == 1 && _handData.NumOppRaisedTurn == 0 &&
                        !_turnCheckRaise && !_flopCheckRaised && strategy == Strategy.Trap)
                    {
                        _turnCheckRaise = true;
                    }
                    else
                    {
                        _turnCheckRaise = false;
                    }
                    MakeTurnDecision();
                }
                else if (_frameData.Round == G.River)
                {
                    if (!_handData.HavePosition && _handData.NumOppRaisedTurn == 1 && _handData.NumOppRaisedRiver == 0  &&
                        !_riverCheckRaise && !_turnCheckRaised && strategy == Strategy.Trap)
                    {
                        _riverCheckRaise = true;
                    }
                    else
                    {
                        _riverCheckRaise = false;
                    }
                    MakeRiverDecision();
                }

            }
            catch (Exception)
            {
                
                ExecuteCheck();
            }
        }
        void ExecuteRaise()
        {
            if (_frameData.CanRaise)
            {
                Agent.DoRaise();
            }
            else
            {
                ExecuteCall();
            }
        }
        void ExecuteCall()
        {
            if (_frameData.CanCall)
            {
                Agent.DoCall();
            }
            else
            {
                ExecuteCheck();
            }
        }
        void ExecuteCheck()
        {
            if (_frameData.CanCheck)
            {
                Agent.DoCheck();
            }
            else
            {
                Agent.DoFold();
            }
        }
    }
}
